Skip to content

[HOTE-977] feat: order confirmed notification#321

Open
usmaana-nhs wants to merge 3 commits intomainfrom
feature/hote-977/order-confirmed-notification
Open

[HOTE-977] feat: order confirmed notification#321
usmaana-nhs wants to merge 3 commits intomainfrom
feature/hote-977/order-confirmed-notification

Conversation

@usmaana-nhs
Copy link
Copy Markdown
Contributor

Description

Context

Type of changes

  • Refactoring (non-breaking change)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would change existing functionality)
  • Bug fix (non-breaking change which fixes an issue)

Checklist

  • I am familiar with the contributing guidelines
  • I have followed the code style of the project
  • I have added tests to cover my changes
  • I have updated the documentation accordingly
  • This PR is a result of pair or mob programming

Sensitive Information Declaration

To ensure the utmost confidentiality and protect your and others privacy, we kindly ask you to NOT including PII (Personal Identifiable Information) / PID (Personal Identifiable Data) or any other sensitive data in this PR (Pull Request) and the codebase changes. We will remove any PR that do contain any sensitive information. We really appreciate your cooperation in this matter.

  • I confirm that neither PII/PID nor sensitive data are included in this PR and the codebase changes.

Copilot AI review requested due to automatic review settings April 7, 2026 11:46
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds “order confirmed” notification publishing from the order-status-lambda, including new notify message payload structure and DB audit persistence to support downstream Notify integration.

Changes:

  • Extend order status handling to accept confirmed and enqueue an OrderConfirmed notify message to SQS.
  • Introduce notification audit DB service and wire it into order-status-lambda init/handler.
  • Update shared notify message types + Zod schema to match the new payload shape.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
local-environment/infra/main.tf Grants lambda permission to publish to the notify SQS queue and injects required env vars locally.
lambdas/src/order-status-lambda/utils.ts Adds CONFIRMED mapping for incoming → internal business status.
lambdas/src/order-status-lambda/types.ts Adds CONFIRMED to allowed incoming/internal status enums.
lambdas/src/order-status-lambda/notify-message-builder.ts Builds OrderConfirmed notify payload (date + tracking link).
lambdas/src/order-status-lambda/notify-message-builder.test.ts Unit test for the notify payload builder.
lambdas/src/order-status-lambda/init.ts Wires SQS client + notification audit DB + required env vars.
lambdas/src/order-status-lambda/init.test.ts Extends init tests for new dependencies and required env vars.
lambdas/src/order-status-lambda/index.ts On confirmed status, fetches notify details, publishes to SQS, and writes an audit record.
lambdas/src/order-status-lambda/index.test.ts Adds handler tests for confirmed status notification/audit behavior and failure cases.
lambdas/src/lib/types/notify-message.ts Refactors notify message shape (top-level nhsNumber, required personalisation).
lambdas/src/lib/types/notify-message-schema.ts Updates Zod schema to validate the new notify message shape.
lambdas/src/lib/types/notify-message-schema.test.ts Updates schema tests to match new payload requirements.
lambdas/src/lib/db/order-status-db.ts Adds getNotifyOrderDetails query used by the lambda when confirmed.
lambdas/src/lib/db/order-status-db.test.ts Unit tests for getNotifyOrderDetails.
lambdas/src/lib/db/notification-audit-db.ts New DB service for inserting notification audit records.
lambdas/src/lib/db/notification-audit-db.test.ts Unit tests for notification audit inserts and failure paths.

Copilot AI review requested due to automatic review settings April 8, 2026 10:31
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 5 comments.

Comment on lines 161 to +170
await orderStatusDb.addOrderStatusUpdate(statusOrderUpdateParams);

commons.logInfo(name, "Order status update added successfully", statusOrderUpdateParams);

await orderStatusNotifyService.handleOrderStatusUpdated({
orderId,
patientId: orderPatientId,
correlationId,
statusUpdate: statusOrderUpdateParams,
});
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If notification publishing/auditing fails, the status update has already been persisted but the handler returns 500; a client retry with the same X-Correlation-ID will hit the idempotency short-circuit and never re-attempt the notification, so the confirmed notification can be dropped permanently. Decouple status persistence from notification side-effects (e.g., outbox/audit written transactionally with the status update and processed asynchronously) or ensure the duplicate-correlationId path still triggers notification retry when no successful (QUEUED/SENT) audit exists.

Copilot uses AI. Check for mistakes.
Comment on lines +104 to +111
await sqsClient.sendMessage(notifyMessagesQueueUrl, JSON.stringify(notifyMessage));

await notificationAuditDbClient.insertNotificationAuditEntry({
messageReference: notifyMessage.messageReference,
eventCode: notifyMessage.eventCode,
correlationId,
status: NotificationAuditStatus.QUEUED,
});
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SQS publish happens before inserting the QUEUED audit row, so if the DB insert fails after a successful send you can end up re-sending the same notification on retry (latest audit is FAILED/absent but the message is already on the queue). To make this idempotent, persist an audit/outbox record before publishing (or in the same DB transaction as the status update), and update/append status after publish so retries can safely detect that a message was already sent/queued.

Suggested change
await sqsClient.sendMessage(notifyMessagesQueueUrl, JSON.stringify(notifyMessage));
await notificationAuditDbClient.insertNotificationAuditEntry({
messageReference: notifyMessage.messageReference,
eventCode: notifyMessage.eventCode,
correlationId,
status: NotificationAuditStatus.QUEUED,
});
await notificationAuditDbClient.insertNotificationAuditEntry({
messageReference: notifyMessage.messageReference,
eventCode: notifyMessage.eventCode,
correlationId,
status: NotificationAuditStatus.QUEUED,
});
await sqsClient.sendMessage(notifyMessagesQueueUrl, JSON.stringify(notifyMessage));

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 8, 2026 10:42
@usmaana-nhs usmaana-nhs force-pushed the feature/hote-977/order-confirmed-notification branch from 81b46c4 to 7c612fa Compare April 8, 2026 10:44
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 8, 2026

Lambdas Coverage Report

Lines Statements Branches Functions
Coverage: 98%
98.39% (1406/1429) 91.86% (418/455) 96.56% (225/233)

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 8, 2026

UI Coverage Report

Lines Statements Branches Functions
Coverage: 95%
95.66% (5732/5992) 87.58% (684/781) 87.86% (210/239)

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.

Comment on lines +75 to +86
async getLatestAuditByCorrelationIdAndEventCode(
correlationId: string,
eventCode: NotifyEventCode,
): Promise<NotificationAuditRecord | null> {
const query = `
SELECT message_reference, event_code, correlation_id, status, created_at
FROM notification_audit
WHERE correlation_id = $1::uuid
AND event_code = $2
ORDER BY created_at DESC
LIMIT 1
`;
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getLatestAuditByCorrelationIdAndEventCode queries by (correlation_id, event_code) and orders by created_at, but the notification_audit table migration only indexes (message_reference, created_at); without a supporting index this lookup will degrade as the audit table grows. Add a DB index aligned to this access pattern (e.g., on (correlation_id, event_code, created_at DESC) or similar) to keep the dedupe check efficient.

Copilot uses AI. Check for mistakes.
@usmaana-nhs usmaana-nhs force-pushed the feature/hote-977/order-confirmed-notification branch from 7c612fa to 3c421d4 Compare April 9, 2026 12:08
@usmaana-nhs usmaana-nhs marked this pull request as ready for review April 9, 2026 12:29
Copilot AI review requested due to automatic review settings April 9, 2026 12:29
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 11 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • ui/package-lock.json: Language not supported

Comment on lines 116 to 124
const notifyMessage = await buildNotifyMessage({
patientId,
correlationId,
orderId,
createdAt: statusUpdate.createdAt,
...(orderedAt ? { orderedAt } : {}),
});

await sqsClient.sendMessage(notifyMessagesQueueUrl, JSON.stringify(notifyMessage));
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Failures from sqsClient.sendMessage() / notificationAuditDbClient.insertNotificationAuditEntry() are caught later in this method and only logged, so the handler will still return 201 even when the notification was not queued/audited and no retry is triggered. Consider rethrowing after logging (or writing an outbox/failure record for async retry) to avoid silently dropping notifications.

Copilot uses AI. Check for mistakes.
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 9, 2026

Copilot AI review requested due to automatic review settings April 9, 2026 14:48
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 11 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • ui/package-lock.json: Language not supported

Comment on lines 114 to +124
private async buildOrderStatusNotifyMessage(input: {
patientId: string;
patientId?: string;
recipient?: NotifyRecipient;
correlationId: string;
orderId: string;
eventCode: NotifyEventCode;
personalisation: Record<string, string>;
}): Promise<NotifyMessage> {
const { patientId, correlationId, eventCode, personalisation } = input;
const { patientId, recipient, correlationId, eventCode, personalisation } = input;

const patient = await this.patientDbClient.get(patientId);
const recipient: NotifyRecipient = {
nhsNumber: patient.nhsNumber,
dateOfBirth: patient.birthDate,
};
const notifyRecipient = recipient ?? (await this.getRecipientFromPatientId(patientId));
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buildOrderStatusNotifyMessage accepts both patientId? and recipient?, but the implementation requires at least one and otherwise throws at runtime; model this constraint in the type (e.g., a union of { patientId: string; recipient?: never } | { recipient: NotifyRecipient; patientId?: never }) so invalid internal calls are caught at compile time.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants